package com.algorithms.datatypes;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import com.algorithms.absdatatypes.Policy;
import com.algorithms.absdatatypes.TreeNode;

public class TreeNodeImpl<K extends Comparable,T>  implements TreeNode<K,T>
{
	

	private K key;
	private T data;
	private TreeNode<K,T> parent =null;
    private LinkedList<TreeNode<K,T>> children =null;
    private boolean visitedFlag=false;
	 
	public T getData()
	{
		return data;
	}

	 
	public boolean isRoot()
	{
		if(getParent()==null)
			return false;
		return true;
	}

	 
	public boolean isLeaf()
	{
		if(getChildren()!=null && getChildren().size()>0)
		 return false;
		return true;
	}

	 
	public TreeNode<K,T> getParent()
	{
		return parent;
	}

	 
	public LinkedList<TreeNode<K,T>> getChildren()
	{
		return children;
	}

	 
	public void setData(T input)
	{
		data=input;
	}

	 
	public void setParent(TreeNode<K,T> input)
	{
		
		parent=input;
	}

	@SuppressWarnings("unchecked")
	 
	public void insertChild(TreeNode<K,T> item)
	{
		item.setParent(this);
		if(children !=null)
		{
			children.add(item);
		}
		else
		{
			children = new LinkedList<TreeNode<K,T>>();
			children.add(item);
			
		}
	}

	 
	public void insertChildren(LinkedList<TreeNode<K,T>> inputChildren)
	{
		/*
		 * First set the parent of all child
		 */
		for(TreeNode<K,T> child: inputChildren)
		{
			child.setParent(this);
		}
		if(children !=null)
		{
			
			children.addAll(inputChildren);
		}
		else
		{
			children =inputChildren;
			
		}
		
	}

	 
	public boolean isVisited()
	{
		return this.visitedFlag;
	}

	 
	public void setVisited(boolean flag)
	{
		this.visitedFlag=flag;
		
	}

	 
	public void apply(Policy<T> policy)
	{
		if(policy!=null)
		{
			policy.execute();
		}
		
	}

	 
	public K getKey()
	{
		
		return key;
	}

	 
	public void setKey(K input)
	{
		key =input;
		
	}

	 
	public boolean equals(Object o) {
		if(o ==this)
		{
			return true;
		}
		if(!(o instanceof TreeNodeImpl ))
		{
			return false;
		}
		TreeNodeImpl<K,T> input =(TreeNodeImpl<K,T>) o;
		return input.getKey()==this.getKey() ;
	}
	 
	public int hashCode() {
		
		int result = hashCode;
		if (result == 0) {
			result = 17;
			result = 31 * result + key.hashCode();
			hashCode = result;
		}
		return result;
	}
	private volatile int hashCode;

	
	
   
}
